package chen.web.install;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import chen.web.SpringDispatcherInit;
import chen.web.config.ConfigRepository;
import chen.web.config.EmailConfig;
import chen.web.config.SiteConfig;
import chen.web.user.Account;
import chen.web.user.AccountManager;
import chen.web.user.AccountManagerImpl;
import chen.web.user.EmailAlreadyBeenRegisteredException;
import chen.web.user.InternalRoleProvider;
import chen.web.user.NicknameAlreadyBeenRegisteredException;
import chen.web.user.RoleManagerImpl;

/**
 * 
 * 系统安装，包括数据库设置，网站信息设置，邮件设置，管理员帐号设置
 * @author chen
 *
 */
public class InstallerlServlet extends HttpServlet{
	
	private static final String ErrorAttributeName = "error";
	
	private ServletContext context = null;
	
	@Override
	public void init(ServletConfig config) throws ServletException {
		// TODO Auto-generated method stub
		context = config.getServletContext();
		super.init(config);
	}

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		if(InstalledFlag.installed()){
			resp.sendError(404);
			return;
		}
		super.service(req, resp);
	}
	
	
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
        // Set to expire far in the past.
        response.setDateHeader("Expires", 0);
        // Set standard HTTP/1.1 no-cache headers.
        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        // Set IE extended HTTP/1.1 no-cache headers (use addHeader).
        response.addHeader("Cache-Control", "post-check=0, pre-check=0");
        // Set standard HTTP/1.0 no-cache header.
        response.setHeader("Pragma", "no-cache");
		String step = request.getParameter("step");
		if(step == null){
			request.getRequestDispatcher("/WEB-INF/install/welcome.jsp").forward(request, response);
			return;
		}
		request.getRequestDispatcher("/WEB-INF/install/step" + Integer.parseInt(step) + ".jsp").forward(request, response);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		int step = Integer.parseInt(req.getParameter("step"));
		boolean success = false;
		switch(step){
		case 1 : {
			success = step1(req, resp);break;
		}
		case 2 : {
			success = step2(req, resp); break;
		}
		case 3 : {
			success = step3(req, resp); break;
		}
		case 4 : {
			success = step4(req, resp); break;
		}
		}
		if(!success){
			gotoStep(req, resp, step);
		}else if(step == 4){//最后一步成功跳转到首页
			resp.sendRedirect(ConfigRepository.instance().get(SiteConfig.class).getBaseURL());
		} else {
			gotoStep(req, resp, step+1);
		}
	}
	
	private void gotoStep(HttpServletRequest req, HttpServletResponse resp, int step) throws ServletException, IOException{
		StringBuilder uri = new StringBuilder("install?step=")
							.append(step);
		Object error = req.getAttribute(ErrorAttributeName);
		if(error != null){
			uri.append("&error=").append(URLEncoder.encode((String)error, "UTF-8"));
		}
		resp.sendRedirect(uri.toString());
	}

	private static final String DriverClassName = "com.mysql.jdbc.Driver";
	private boolean step1(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
		String host = request.getParameter("host");
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		int port = Integer.parseInt(request.getParameter("port"));
		String database = request.getParameter("database");
		
		try{
			Class.forName(DriverClassName);	
		}catch(ClassNotFoundException ex){
			throw new RuntimeException("找不到驱动程序", ex);
		}

		//测试能否连接mysql
		String url = "jdbc:mysql://" + host + ":" + port + "/" + database;
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		try{
			conn = DriverManager.getConnection(url, username, password);
			stmt = conn.createStatement();
			rs = stmt.executeQuery("select count(*) from web_account");
		}catch(SQLException ex){
			request.setAttribute(ErrorAttributeName, "无法与数据建立连接，请检查数据库配置");
			return false;
		} finally{
			try{
				if(rs != null)rs.close();
				if(stmt != null) stmt.close();
				if(conn != null) conn.close();	
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				throw new RuntimeException(e);
			}
		}
		
		String path = this.getClass().getResource("/jdbc.properties").getPath();
		Properties p = new Properties();
		p.load(new FileInputStream(path));
		p.setProperty("jdbc.DriverClassName", DriverClassName);
		p.setProperty("jdbc.url", url);
		p.setProperty("jdbc.username", username);
		p.setProperty("jdbc.password", password);
		p.store(new FileOutputStream(path), null);

		//初始化spring容器
		SpringDispatcherInit.init(context);
		return true;
	}
	
	private boolean step2(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
		String adminEmail = request.getParameter("adminEmail");
		String baseURL = request.getParameter("baseURL");
		String description = request.getParameter("description");
		String siteName = request.getParameter("siteName");
		
		SiteConfig config = new SiteConfig.Builder().adminEmail(adminEmail)
													.baseURL(baseURL)
													.description(description)
													.siteName(siteName)
													.build();
		ConfigRepository.instance().put(config);
		return true;
	}
	
	private boolean step3(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
		boolean useSMTP = Boolean.valueOf(request.getParameter("useSMTP"));
		String address = request.getParameter("address");
		String host = request.getParameter("host");
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		
		EmailConfig config = new EmailConfig.Builder().useSMTP(useSMTP)
													.senderEmail(address)
													.smtpHost(host)
													.username(username)
													.password(password)
													.build();
													
		ConfigRepository.instance().put(config);
		return true;
	}
	
	private boolean step4(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
		String nickname = request.getParameter("nickname");
		String password = request.getParameter("password");

		try {
			AccountManager am = new AccountManagerImpl(new RoleManagerImpl());
			Account admin = am.register(nickname, password, ConfigRepository.instance().get(SiteConfig.class).getAdminEmail());
			am.changeRole(admin, InternalRoleProvider.getAdminRole());
		} catch (NicknameAlreadyBeenRegisteredException e) {
			// TODO Auto-generated catch block
			request.setAttribute(ErrorAttributeName, "用户名已经被注册");
			return false;
		} catch (EmailAlreadyBeenRegisteredException e) {
			// TODO Auto-generated catch block
			request.setAttribute(ErrorAttributeName, "Email地址已经被注册");
			return false;
		}
		InstalledFlag.setInstalled();
		return true;
	}

}
